package com.zxc.oauth.service.impl

import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import com.zxc.oauth.exception.OAuthException
import com.zxc.oauth.exception.OAuthExceptionCode
import com.zxc.oauth.model.CurrentUser
import com.zxc.oauth.model.OAuthConstant
import com.zxc.oauth.model.TokenType
import com.zxc.oauth.properties.OauthUserProperties
import com.zxc.oauth.service.OauthToken
import com.zxc.oauth.service.TokenService
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.time.Instant

class UserTokenService(
    private val OauthUserProperties: OauthUserProperties
): TokenService<CurrentUser> {

    private val logger: Logger = LoggerFactory.getLogger(this::class.java)

    private val jwtHs256 = Algorithm.HMAC256(OauthUserProperties.accessTokenSecret)

    //可重用的验证程序实例
    private val jwtVerifier = JWT.require(jwtHs256).build()

    override fun createAccessToken(t: CurrentUser): OauthToken {
        try {

            val token = JWT.create()
                .withClaim(OAuthConstant.aid, t.id)
                .withClaim(OAuthConstant.name, t.name)
                .withClaim(OAuthConstant.exp, Instant.now().plusSeconds(OauthUserProperties.accessTokenExpiresIn!!).epochSecond)
                .sign(jwtHs256)

            return OauthToken(token = token, expiresIn = OauthUserProperties.accessTokenExpiresIn!!)
        }catch (e: Exception){
            throw OAuthException(OAuthExceptionCode.LOGIN_ERROR, e)
        }
    }

    override fun createRefreshToken(t: CurrentUser): OauthToken {
        try {

            val token = JWT.create()
                .withClaim(OAuthConstant.uid, t.id)
                .withClaim(OAuthConstant.exp, Instant.now().plusSeconds(OauthUserProperties.refreshTokenExpiresIn!!).epochSecond)
                .sign(jwtHs256)

            return OauthToken(token = token, expiresIn = OauthUserProperties.refreshTokenExpiresIn!!)
        }catch (e: Exception){
            throw OAuthException(OAuthExceptionCode.LOGIN_ERROR, e)
        }
    }

    override fun accessTokenVerify(content: String): Boolean {
        try {

            val token = getTokenContent(content)
            val jwt = jwtVerifier.verify(token)
            val expire = jwt.getClaim(OAuthConstant.exp).asLong()

            if(expire < Instant.now().epochSecond){
                throw OAuthException(OAuthExceptionCode.USER_AUTH_FAILED)
            }
            return true
        }catch (e: Exception){
            throw OAuthException(OAuthExceptionCode.USER_AUTH_FAILED, e)
        }
    }

    override fun accessTokenDecode(content: String): CurrentUser {
        try {

            val token = getTokenContent(content)
            val jwt = jwtVerifier.verify(token)
            val expire = jwt.getClaim(OAuthConstant.exp).asLong()

            if(expire < Instant.now().epochSecond){
                throw OAuthException(OAuthExceptionCode.USER_AUTH_FAILED)
            }
            val userId = jwt.getClaim(OAuthConstant.uid).asLong()
            val userName = jwt.getClaim(OAuthConstant.name).asString()
            return CurrentUser(id = userId, name = userName)
        }catch (e: Exception){
            throw OAuthException(OAuthExceptionCode.USER_AUTH_FAILED, e)
        }
    }

    override fun refreshTokenDecode(content: String): CurrentUser {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    /**
     * token 的格式 Bearer 在外加一个空格字符
     * Bearer TOKEN
     */
    private fun getTokenContent(bearerToken: String): String{
        return bearerToken.substring(TokenType.Bearer.getValue().length + 1)
    }
}